#include "edfmodel.h"

#include <string>
#include <iostream>
#include <fstream>

#include <math.h>

namespace biosignal {
namespace edf {

using namespace std;

class EDFTimeKeepingData {
    friend class EDFModel;
public:
    long calculate_data_record(double time) const {
        long data_record = -1;
        if (!edf_model->has_interruptions()) {
            data_record = (long) (time / edf_model->datarecord_duration());
        }
        return data_record;
    }
private:
    EDFModel_Ptr edf_model;
    std::vector<double> onsets;
};

EDFModel::EDFModel(const char* file_name) :
        BioSignal(file_name) {
    ifstream* ifs = new ifstream(file_name, ifstream::in);
    this->biosignal_istream = istream_ptr(ifs);
    cout << ifs->is_open() << " " << endl;
}
EDFModel::~EDFModel() {
}

//candidate to Template param
DataFrame* EDFModel::create_dataframe(TimePeriod bounds, shared_ptr<
                                      const montage::Montage> montage) const {
    DataFrame* df = new EDFDataRecord(this, bounds, montage);
    return df;
}

void EDFModel::open_file_as_binary() {
    biosignal_istream = istream_ptr(new ifstream(file_name_.c_str(),
                                    ifstream::binary));
    cout << "open_file_as_binary  tellg : " << biosignal_istream->tellg()
         << endl;
}

bool EDFModel::is_edf_plus() const {
    return m_is_edf_plus;
}

bool EDFModel::has_interruptions() const {
    return (m_is_edf_plus && m_has_interruptions);
}

double EDFModel::datarecord_duration() const {
    return m_data_record_duration;
}
long EDFModel::get_nr_dataframes() const {
    return m_nr_data_records;
}

void EDFModel::show_header_info(ostream& os) const {
    os << " version : " << "|" << this->m_version << "|" << endl;
    os << " patient_identification : " << "|" << this->m_patient_identification
    << "|" << endl;
    os << " recording_identification : " << "|"
    << this->m_recording_identification << "|" << endl;
    os << " recording_time : " << "|" << this->m_recording_time << "|" << endl;
    os << " bytes_in_header : " << "|" << this->m_bytes_in_header << "|"
    << endl;
    os << " reserved : " << "|" << this->m_reserved << "|" << endl;
    os << " is_edf_plus : " << this->m_is_edf_plus << endl;
    os << " has_interruptions : " << this->m_has_interruptions << endl;
    os << " nr_data_records : " << "|" << this->get_nr_dataframes() << "|"
    << endl;
    os << " data_record_duration : " << "|" << this->m_data_record_duration
    << "|" << endl;
    os << " nr_signals : " << this->signals_group().size() << endl;
    os << "============ signals ============" << endl;
    SignalsGroup::const_iterator it;
    for (it = signals_group().begin(); it != signals_group().end(); ++it) {
        EDFSourceSignal* esi = dynamic_cast<EDFSourceSignal*> (it->get());
        os << " " << esi->label() << " " << esi->physical_dimension();
        os << " " << esi->physical_minimum() << " " << esi->physical_maximum();
        os << " " << esi->digital_minimum() << " " << esi->digital_maximum();
        os << " " << esi->prefiltering() << " "
        << esi->nr_samples_in_data_record();
        os << endl;
    }
    os << "!!!========= signals =========!!!" << endl;
}
/*
 EDFModel::data_record_Ptr EDFModel::get_data_record(long data_record) {
 data_record_Ptr returned_data_record(new data_record(data_record, data_record*10.1));
 return returned_data_record;
 }
 */

TimePeriod EDFModel::dataframe_time_period(TimePoint time) const throw (BadTimePoint) {
    if (!recording_time().contains(time))
        throw BadTimePoint();
    double seconds = (time-recording_time().begin()).total_seconds();
    TimePeriod result;
    if (!has_interruptions()) {
        long dataframe = seconds / m_data_record_duration;
	TimeOffset dfduration = TimeOffset::Seconds(m_data_record_duration);
	result = TimePeriod(recording_time().begin()+TimeOffset::Seconds(dataframe*m_data_record_duration), dfduration);
    } else {
        throw NotImplementedException("get_dataframe with interruptions !!");
    }
    return result;

}

}
}
